﻿#region License

// Dimebrain TweetSharp
// (www.dimebrain.com)
// 
// The MIT License
// 
// Copyright (c) 2009 Dimebrain
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// 

#endregion

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
#if !SILVERLIGHT
using System.Web;
#endif
using Dimebrain.TweetSharp.Core.Extensions;
using Dimebrain.TweetSharp.Core.OAuth;

namespace Dimebrain.TweetSharp.Core.Web.Query.OAuth
{
    /// <summary>
    /// A web query engine for OAuth requests.
    /// </summary>
    public class OAuthWebQuery : WebQueryBase
    {
        public string Realm { get; set; }

        public OAuthWebQuery(OAuthWebQueryInfo info) : base(info)
        {
            Method = info.WebMethod;
        }

        // todo duplicated in OAuthWebQueryClient, consolidate
        protected override WebRequest BuildPostWebRequest(string url, out byte[] content)
        {
            // remove POST parameters from query
            var uri = url.AsUri();
            url = uri.Scheme.Then("://")
#if !SILVERLIGHT
                .Then(uri.Authority)
#else
                .Then(uri.Host)
#endif
            ;
            if (uri.Port != 80)
                url = url.Then(":" + uri.Port);
            url = url.Then(uri.AbsolutePath);
            
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

#if !SILVERLIGHT
            if (!Proxy.IsNullOrBlank())
            {
                request.Proxy = new WebProxy(Proxy);
                SetAuthorizationHeader(request, "Proxy-Authorization");
            }
#endif
            foreach (var header in Headers)
            {
#if !SILVERLIGHT
                request.Headers.Add(header.Key, header.Value);
#else
                request.Headers[header.Key] = header.Value;
#endif
            }

            if (!UserAgent.IsNullOrBlank())
            {
#if !SILVERLIGHT
                request.UserAgent = UserAgent;
#else
                request.Headers["User-Agent"] = UserAgent;
#endif
            }

            if(UseCompression)
            {
#if !SILVERLIGHT
                request.AutomaticDecompression = DecompressionMethods.GZip;
#else
                request.Accept = "gzip,deflate";
#endif
            }

            SetAuthorizationHeader(request, "Authorization");

            // Only use the POST parameters in the body
            var postParameters = new WebParameterCollection
#if SILVERLIGHT
                (uri.Query.ParseQueryString());
#else
                (HttpUtility.ParseQueryString(uri.Query));
#endif

            var body = "";
            var parameters = 0;
            foreach(var postParameter in postParameters)
            {
                var name = Uri.EscapeDataString(postParameter.Name);
                var value = Uri.EscapeDataString(postParameter.Value);

                body = body.Then("{0}={1}".FormatWith(name, value));
                
                if(parameters < postParameters.Count - 1)
                {
                    body = body.Then("&");
                }

                parameters++;
            }

            content = Encoding.UTF8.GetBytes(body);
#if !SILVERLIGHT
            // note Silverlight sets this dynamically
            request.ContentLength = content.Length;
#endif
            return request;
        }

        protected override void SetAuthorizationHeader(WebRequest request, string header)
        {
            var sb = new StringBuilder("OAuth ");
            if(!Realm.IsNullOrBlank())
            {
                sb.Append("realm=\"{0}\",".FormatWith(OAuthTools.UrlEncode(Realm)));
            }

            var parameters = 0;
            foreach (var parameter in Parameters)
            {
                if(parameter.Name.IsNullOrBlank() || parameter.Value.IsNullOrBlank())
                {
                    continue;
                }

                parameters++;
                var format = parameters < Parameters.Count ? "{0}=\"{1}\"," : "{0}=\"{1}\"";
                sb.Append(format.FormatWith(parameter.Name, parameter.Value));
            }

            var authorization = sb.ToString();
            AuthorizationHeader = authorization;

#if !SILVERLIGHT
            request.Headers["Authorization"] = AuthorizationHeader;
#else
            request.Headers["X-Twitter-Auth"] = AuthorizationHeader;
#endif
        }

        protected override HttpWebRequest BuildMultiPartFormRequest(string url, IEnumerable<HttpPostParameter> parameters, out byte[] bytes)
        {
            var boundary = Guid.NewGuid().ToString();
            var request = (HttpWebRequest)WebRequest.Create(url);

#if !SILVERLIGHT
            // todo we can probably remove these anyway
            request.PreAuthenticate = true;
            request.AllowWriteStreamBuffering = true;
#endif
            request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
            request.Method = "POST";

            SetAuthorizationHeader(request, "Authorization");

            var contents = BuildMultiPartFormRequestParameters(boundary, parameters);
            var payload = contents.ToString();

            bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(payload);

#if !SILVERLIGHT
            request.ContentLength = bytes.Length;
#endif
            return request; 
        }
    }
}